home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / wu-ftpd-.000 / wu-ftpd- / wu-ftpd-2.4-fixed / support / ftw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-03  |  7.0 KB  |  353 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #if defined(LIBC_SCCS) && !defined(lint)
  19. static char sccsid[] = "@(#)ftw.c    5.3 (Berkeley) 8/5/88";
  20.  
  21. #endif /* LIBC_SCCS and not lint */
  22.  
  23. #include "../src/config.h"
  24.  
  25. #ifdef HAVE_DIRENT
  26. #include <dirent.h>
  27. #else
  28. #include <sys/dir.h>
  29. #endif
  30.  
  31. #include <errno.h>
  32.  
  33. #include <sys/param.h>
  34. #include <sys/stat.h>
  35. #include <sys/stat.h>
  36.  
  37. #include "ftw.h"
  38.  
  39. #define    NODESC    -1
  40.  
  41. #ifdef HAVE_SYMLINK
  42. # define    ISLINK(sb)    ((sb.st_mode&S_IFMT) == S_IFLNK)
  43. #else
  44. # define lstat stat
  45. #endif
  46.  
  47. #define    ISDIR(sb)    ((sb.st_mode&S_IFMT) == S_IFDIR)
  48. #define    ISDOT(dp) \
  49.     (dp->d_name[0] == '.' && (!dp->d_name[1] || \
  50.         (dp->d_name[1] == '.' && !dp->d_name[2])))
  51.  
  52. extern int errno;
  53. static int g_fds,
  54.   (*g_fn) (),
  55.   g_opts;
  56. static char *bp;
  57.  
  58. int treewalk(char *path, int (*fn) ( /* ??? */ ), int maxfds, int opts);
  59.  
  60. /*
  61.  * cycle through the directories at the top of the tree, otherwise, once
  62.  * you run out of descriptors you have to keep reusing the same one and
  63.  * it gets *real* slow.
  64.  */
  65. typedef struct d_fd {
  66.     struct d_fd *next;
  67.     DIR *dirp;
  68.     off_t off;
  69. } FD;
  70.  
  71. static FD *freep,
  72.  *node;
  73.  
  74. static int
  75. walk(register char *name)
  76. {
  77. #ifdef HAVE_DIRENT
  78.     register struct dirent *dp;
  79. #else
  80.     register struct direct *dp;
  81. #endif
  82.     register int rval;
  83.     struct stat sb;
  84.     FD cur;
  85.     char *save,
  86.      *strcpy(char *, const char *);
  87.  
  88.     if (!freep)
  89.         freep = &cur;
  90.     else
  91.         node->next = &cur;
  92.     node = &cur;
  93.     cur.off = 0;
  94.  
  95.   getfd:if (!g_fds) {
  96.         freep->off = telldir(freep->dirp);
  97.         closedir(freep->dirp);
  98.         freep = freep->next;
  99.         ++g_fds;
  100.     }
  101.     if ( !(cur.dirp = opendir(bp)) ) {
  102.         if (errno == EMFILE) {
  103.             g_fds = 0;
  104.             goto getfd;
  105.         }
  106.         return (errno == EACCES ? (*g_fn) (bp, &sb, FTW_DNR) : -1);
  107.     } else
  108.         --g_fds;
  109.  
  110.     for (; *name; ++name) ;
  111.     *name++ = '/';
  112.     for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
  113.         if (ISDOT(dp))
  114.             continue;
  115.         (void) strcpy(name, dp->d_name);
  116.         if (lstat(bp, &sb)) {
  117.             rval = errno == EACCES ?
  118.                 (*g_fn) (bp, &sb, FTW_NS) : -1;
  119.             if (rval)
  120.                 break;
  121.         }
  122. #ifdef HAVE_SYMLINK
  123.         if (ISLINK(sb) && g_opts & FTW_SYMLINK)
  124.             if (stat(bp, &sb))
  125.                 continue;
  126. #endif
  127.         if (!ISDIR(sb)) {
  128.             rval = (*g_fn) (bp, &sb, FTW_F);
  129.             if (rval)
  130.                 break;
  131.             continue;
  132.         }
  133.         if (g_opts & FTW_DIRLAST)
  134. #ifdef HAVE_D_NAMLEN
  135.             save = name + dp->d_namlen;
  136. #else
  137.             save = name + strlen(dp->d_name);
  138. #endif
  139.         rval = (*g_fn) (bp, &sb, FTW_D);
  140.         if ( (rval && rval != NODESC) || (rval = walk(name)))
  141.             break;
  142.         if (g_opts & FTW_DIRLAST) {
  143.             *save = '\0';
  144.             rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
  145.             if (rval)
  146.                 if (rval == NODESC)
  147.                     rval = 0;
  148.                 else
  149.                     break;
  150.         }
  151.         if (cur.off) {
  152.             *name = (char) NULL;
  153.             if ( (cur.dirp = opendir(bp)) ) {
  154.                 seekdir(cur.dirp, cur.off);
  155.                 /* tricky; if we have to reset the directory pointer we know
  156.                  * it's the next one to reuse */
  157.                 freep = &cur;
  158.                 --g_fds;
  159.             }
  160.             /* directory moved from under us!!! */
  161.             else {
  162.                 rval = -1;
  163.                 break;
  164.             }
  165.         }
  166.     }
  167.     closedir(cur.dirp);
  168.     ++g_fds;
  169.     return (rval);
  170. }
  171.  
  172. static int
  173. chwalk(register char *name)
  174. {
  175. #ifdef HAVE_DIRENT
  176.     register struct dirent *dp;
  177. #else
  178.     register struct direct *dp;
  179. #endif
  180.  
  181.     register int rval;
  182.     struct stat sb;
  183.     FD cur;
  184.     char *pwd,
  185.      *getwd(char *),
  186. #ifndef NO_MALLOC_PROTO
  187.      *malloc(size_t),
  188. #endif
  189.      *strcpy(char *, const char *);
  190.  
  191.     if (!freep)
  192.         freep = &cur;
  193.     else
  194.         node->next = &cur;
  195.     node = &cur;
  196.     cur.off = 0;
  197.  
  198.     if (chdir(name))
  199.         return (errno == EACCES ? (*g_fn) (name, &sb, FTW_DNR) : -1);
  200.  
  201.   getfd:if (!g_fds) {
  202.         freep->off = telldir(freep->dirp);
  203.         closedir(freep->dirp);
  204.         freep = freep->next;
  205.         ++g_fds;
  206.     }
  207.     if ( !(cur.dirp = opendir(".")) )  {
  208.         if (errno == EMFILE) {
  209.             g_fds = 0;
  210.             goto getfd;
  211.         }
  212.         return (errno == EACCES ? (*g_fn) (".", &sb, FTW_DNR) : -1);
  213.     } else
  214.         --g_fds;
  215.  
  216.     for (rval = 0, dp = readdir(cur.dirp); dp; dp = readdir(cur.dirp)) {
  217.         if (ISDOT(dp))
  218.             continue;
  219.         if (lstat(dp->d_name, &sb)) {
  220.             rval = errno == EACCES ?
  221.                 (*g_fn) (dp->d_name, &sb, FTW_NS) : -1;
  222.             if (rval)
  223.                 break;
  224.         }
  225.         pwd = NULL;
  226. #ifdef HAVE_SYMLINK
  227.         if (ISLINK(sb) && g_opts & FTW_SYMLINK) {
  228.             if (stat(dp->d_name, &sb))
  229.                 continue;
  230.             if (ISDIR(sb)) {
  231.                 /* NOSTRICT */
  232.                 if (!(pwd = malloc((u_int) MAXPATHLEN))) {
  233.                     rval = -1;
  234.                     break;
  235.                 }
  236.                 if (!getwd(pwd)) {
  237.                     rval = -1;
  238.                     break;
  239.                 }
  240.             }
  241.         }
  242. #endif
  243.         if (!ISDIR(sb)) {
  244.             rval = (*g_fn) (dp->d_name, &sb, FTW_F);
  245.             if (rval)
  246.                 break;
  247.             continue;
  248.         }
  249.         rval = (*g_fn) (dp->d_name, &sb, FTW_D);
  250.         if ((rval && rval != NODESC) || (rval = chwalk(dp->d_name)))
  251.             break;
  252.         if (g_opts & FTW_DIRLAST) {
  253.             rval = (*g_fn) (dp->d_name, &sb, FTW_D2);
  254.             if (rval)
  255.                 if (rval == NODESC)
  256.                     rval = 0;
  257.                 else
  258.                     break;
  259.         }
  260.         if (pwd && chdir(pwd)) {
  261.             rval = -1;
  262.             break;
  263.         }
  264.         if (cur.off) {
  265.             if ( (cur.dirp = opendir(".")) ) {
  266.                 seekdir(cur.dirp, cur.off);
  267.                 /* tricky; if we have to reset the directory pointer we know
  268.                  * it's the next one to reuse */
  269.                 freep = &cur;
  270.                 --g_fds;
  271.             }
  272.             /* directory moved from under us!!! */
  273.             else {
  274.                 rval = -1;
  275.                 break;
  276.             }
  277.         }
  278.     }
  279.     closedir(cur.dirp);
  280.     ++g_fds;
  281.     if (chdir(".."))
  282.         return (-1);
  283.     return (rval);
  284. }
  285.  
  286. /* S5 compatible ftw(BA_LIB) */
  287. int
  288. ftw(char *path, int (*fn) ( /* ??? */ ), int maxfds)
  289. {
  290.     return (treewalk(path, fn, maxfds, 0));
  291. }
  292.  
  293. int
  294. treewalk(char *path, int (*fn) ( /* ??? */ ), int maxfds, int opts)
  295. {
  296.     struct stat sb;
  297.     int rval;
  298.     char *pwd,
  299.      *getwd(char *),
  300. #ifndef NO_MALLOC_PROTO
  301.      *malloc(size_t),
  302. #endif
  303.      *strcpy(char *, const char *);
  304.  
  305.     if (lstat(path, &sb))
  306.         return (errno == EACCES ? (*fn) (path, &sb, FTW_NS) : -1);
  307.  
  308.     pwd = NULL;
  309. #ifdef HAVE_SYMLINK
  310.     if (ISLINK(sb) && opts & FTW_SYMLINK) {
  311.         if (stat(path, &sb))
  312.             return (0);
  313.         if (ISDIR(sb)) {
  314.             /* NOSTRICT */
  315.             if (!(pwd = malloc((u_int) MAXPATHLEN)))
  316.                 return (-1);
  317.             if (!getwd(pwd))
  318.                 return (-1);
  319.         }
  320.     }
  321. #endif
  322.     if (!ISDIR(sb))
  323.         return ((*fn) (path, &sb, FTW_F));
  324.  
  325.     if (!maxfds)
  326.         return (-1);
  327.     g_fds = maxfds == -1 ? getdtablesize(): maxfds;
  328.     g_fn = fn;
  329.     g_opts = opts;
  330.  
  331.     if (!(opts & FTW_CHDIR) && !(bp = malloc((u_int) MAXPATHLEN))) {
  332.         errno = ENOMEM;
  333.         return (-1);
  334.     }
  335.     rval = (*fn) (path, &sb, FTW_D);
  336.     if (rval == NODESC)
  337.         rval = 0;
  338.     else if (!rval) {
  339.         if (opts & FTW_CHDIR)
  340.             rval = chwalk(path);
  341.         else
  342.             rval = walk(strcpy(bp, path));
  343.         if (!rval && opts & FTW_DIRLAST) {
  344.             rval = (*fn) (path, &sb, FTW_D2);
  345.             if (rval == NODESC)
  346.                 rval = 0;
  347.         }
  348.     }
  349.     if (pwd && chdir(pwd))
  350.         return (-1);
  351.     return (rval);
  352. }
  353.